import time
import json
from typing import Dict, Any, Optional
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.tiia.v20190529 import tiia_client, models
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from app.core.config import settings
from .config import tencent_settings

class TencentImageRecognitionService:
    """腾讯云图像识别服务"""
    
    def __init__(self):
        self.client = self._create_client()
    
    def _create_client(self) -> tiia_client.TiiaClient:
        """创建腾讯云TIIA客户端"""
        try:
            # 认证信息
            cred = credential.Credential(
                tencent_settings.secret_id,
                tencent_settings.secret_key
            )
            
            # HTTP配置
            httpProfile = HttpProfile()
            httpProfile.endpoint = tencent_settings.tiia_endpoint
            
            # 客户端配置
            clientProfile = ClientProfile()
            clientProfile.httpProfile = httpProfile
            
            # 创建客户端
            client = tiia_client.TiiaClient(cred, tencent_settings.region, clientProfile)
            return client
            
        except Exception as e:
            raise Exception(f"创建腾讯云客户端失败: {str(e)}")
    
    def detect_objects(self, image_base64: str) -> Dict[str, Any]:
        """物体检测"""
        try:
            req = models.DetectProductRequest()
            req.ImageBase64 = image_base64
            
            resp = self.client.DetectProduct(req)
            return json.loads(resp.to_json_string())
            
        except TencentCloudSDKException as e:
            raise Exception(f"物体检测失败: {e}")
    
    def search_image(self, image_base64: str, group_id: str) -> Dict[str, Any]:
        """图像搜索"""
        try:
            req = models.SearchImageRequest()
            req.GroupId = group_id
            req.ImageBase64 = image_base64
            req.Limit = 10  # 返回结果数量
            
            resp = self.client.SearchImage(req)
            return json.loads(resp.to_json_string())
            
        except TencentCloudSDKException as e:
            raise Exception(f"图像搜索失败: {e}")
    
    def create_image_group(self, group_id: str, group_name: str) -> Dict[str, Any]:
        """创建图片库"""
        try:
            req = models.CreateGroupRequest()
            req.GroupId = group_id
            req.GroupName = group_name
            req.MaxCapacity = 100000  # 最大容量
            
            resp = self.client.CreateGroup(req)
            return json.loads(resp.to_json_string())
            
        except TencentCloudSDKException as e:
            raise Exception(f"创建图片库失败: {e}")
    
    def _safe_pic_name(self, pic_name: Optional[str], entity_id: str, max_len: int = 64) -> str:
        """确保 PicName 不超过限制长度，超长时尾部加时间戳截断"""
        name = pic_name or f"{entity_id}_{int(time.time())}"
        if len(name) <= max_len:
            return name
        suffix = f"_{int(time.time())}"
        available = max_len - len(suffix)
        if available <= 0:
            return name[:max_len]
        return name[:available] + suffix

    # 新增：规范化并限制 Tags 长度（每个值与整体长度）
    def _normalize_tags_payload(self, tags, max_value_len: int = 200, max_total_len: int = 1000) -> Optional[str]:
        """
        将 tags 规范化为 JSON 对象字符串：
        - 任意输入（str/list/dict/其他）都会被转换为 dict，值为字符串
        - 每个 value 限制最大长度
        - 整体 JSON 字符串也限制最大长度，必要时优先截断 keywords
        """
        def to_flat_str(v) -> str:
            if isinstance(v, list):
                return ",".join([str(x).strip() for x in v if str(x).strip()])
            if isinstance(v, dict):
                # dict 作为值时转 JSON 再入字符串
                return json.dumps(v, ensure_ascii=False)
            return str(v)

        # 包装为 dict
        if not isinstance(tags, dict):
            base = {"keywords": to_flat_str(tags)}
        else:
            base = {}
            for k, v in tags.items():
                key = str(k).strip()
                if not key:
                    continue
                base[key] = to_flat_str(v)

        # 截断每个 value 长度
        for k, v in list(base.items()):
            if not isinstance(v, str):
                v = str(v)
            base[k] = v[:max_value_len]

        # 序列化并控制整体大小（以 UTF-8 字节长度为准）
        def dump_bytes(d: dict) -> bytes:
            return json.dumps(d, ensure_ascii=False).encode("utf-8")

        b = dump_bytes(base)
        if len(b) <= max_total_len:
            return b.decode("utf-8")

        # 优先缩短 keywords
        if "keywords" in base and isinstance(base["keywords"], str):
            # 逐步缩短直到满足上限或为空
            for _ in range(100):
                over = len(b) - max_total_len
                if over <= 0:
                    break
                if not base["keywords"]:
                    break
                # 每次截断一定长度，防止循环次数过多
                cut = max(1, min(over, 50))
                base["keywords"] = base["keywords"][:-cut]
                b = dump_bytes(base)

        # 如果还是超出，就删除除 keywords 外的其他键
        if len(b) > max_total_len:
            keys = [k for k in base.keys() if k != "keywords"]
            for k in keys:
                base.pop(k, None)
                b = dump_bytes(base)
                if len(b) <= max_total_len:
                    break

        # 最后兜底，再不行就硬截 keywords
        if len(b) > max_total_len and "keywords" in base and isinstance(base["keywords"], str):
            # 粗暴按字节预算截断
            budget = max_total_len - len(json.dumps({"keywords": ""}, ensure_ascii=False).encode("utf-8"))
            base["keywords"] = base["keywords"].encode("utf-8")[:max(0, budget)].decode("utf-8", errors="ignore")
            b = dump_bytes(base)

        return b.decode("utf-8")

    def add_image_to_group(self, group_id: str, entity_id: str, image_base64: str, 
                          pic_name: Optional[str] = None) -> Dict[str, Any]:
        """添加图片到图片库"""
        try:
            print(f"尝试添加图片到图库: {group_id}")  # 调试日志
            req = models.CreateImageRequest()
            req.GroupId = group_id
            req.EntityId = entity_id
            req.ImageBase64 = image_base64
            # 统一使用安全的 PicName
            req.PicName = self._safe_pic_name(pic_name, entity_id, max_len=64)
            
            # 不再上传 Tags
            # req.Tags = ...

            resp = self.client.CreateImage(req)
            return json.loads(resp.to_json_string())
            
        except TencentCloudSDKException as e:
            raise Exception(f"添加图片失败: {e}")
    
    def describe_groups(self, offset: int = 0, limit: int = 10, group_id: Optional[str] = None) -> Dict[str, Any]:
        """查询图片库列表"""
        try:
            req = models.DescribeGroupsRequest()
            req.Offset = offset
            req.Limit = limit
            if group_id:
                req.GroupId = group_id
            
            resp = self.client.DescribeGroups(req)
            return json.loads(resp.to_json_string())
            
        except TencentCloudSDKException as e:
            raise Exception(f"查询图片库失败: {e}")
    
    def describe_images(self, group_id: str, entity_id: str, pic_name: Optional[str] = None) -> Dict[str, Any]:
        """查询图片信息"""
        try:
            req = models.DescribeImagesRequest()
            req.GroupId = group_id
            req.EntityId = entity_id
            if pic_name:
                req.PicName = pic_name
            
            resp = self.client.DescribeImages(req)
            return json.loads(resp.to_json_string())
            
        except TencentCloudSDKException as e:
            raise Exception(f"查询图片信息失败: {e}")
    
    # 删除这两个方法：
    # def delete_image(self, group_id: str, entity_id: str, pic_name: str) -> Dict[str, Any]:
    # def update_image(self, group_id: str, entity_id: str, pic_name: str, 
    #                 image_base64: str, tags: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
        """更新图片信息（仅支持修改Tags）"""
        try:
            # 使用正确的修改图片信息接口
            req = models.UpdateImageRequest()  # 或者可能是 ModifyImageRequest
            req.GroupId = group_id
            req.EntityId = entity_id
            req.PicName = pic_name
            
            if tags:
                req.Tags = json.dumps(tags)
            
            resp = self.client.UpdateImage(req)  # 或者对应的方法名
            return json.loads(resp.to_json_string())
            
        except TencentCloudSDKException as e:
            raise Exception(f"更新图片失败: {e}")